﻿#define Download

using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Halk.Analyser;
using Halk.Config;
using Halk.Model;

namespace Halk.Spider
{
    public class NovelSpider : SpiderBase
    {
        private class AnalyserAll
        {
            public int DiffCount { get; set; }
            public AnalyseArticle AnalyseArticler { get; set; }
            public AnalyseBookReader AnalyseBookReaderer { get; set; }
            public AnalyseChapter AnalyseChapter { get; set; }
        }

        private readonly Dictionary<string, AnalyserAll> _dicAnalyser = new Dictionary<string, AnalyserAll>();

        private void Initialize()
        {
            Config.ConfigManage.Instace().Load();
            Config.ContentManage.Instace().Load();

            var rulePath = string.Format("conf/rule/{0}.xml", Config.ConfigManage.Instace().GetConfig().RuleFlag);
            FirstRule = RuleManage.Instace().GetRuleFormXml(rulePath);
        }

        public void Work()
        {
            Initialize();
            while (Config.AppCache.Instace().GetOnOff())
            {
                RepeatTimes = 0;
                FirstAnalyseArticleList.Rule = FirstRule;
                FirstAnalyseArticle.Rule = FirstRule;
                FirstAnalyseBookReader.Rule = FirstRule;
                FirstAnalyseChapter.Rule = FirstRule;

                //test
                //string content = Utils.HttpHelper.Get("http://www.kenwen.com/cview/35/35320/5414837.html",Encoding.GetEncoding("gbk"));
                GetNovelList(ref _firstAnalyseArticleList,
                             ref _firstAnalyseArticle,
                             ref _firstAnalyseBookReader,
                             ref _firstAnalyseChapter);
            }
        }

        private void GetNovelList(ref AnalyseArticlelist analyseArticleList,
                                  ref AnalyseArticle analyseArticle,
                                  ref AnalyseBookReader analyseBookReader,
                                  ref AnalyseChapter analyseChapter)
        {
            var listUrl = analyseArticleList.GetNovelListUrl();
            for (var iPage = 1; iPage < Config.ConfigManage.Instace().GetConfig().MaxPage; ++iPage)
            {
                listUrl = listUrl.Replace("(*)", iPage.ToString(CultureInfo.InvariantCulture));
                analyseArticleList.SetContent(Utils.HttpHelper.Get(listUrl, analyseArticleList.Encode));
                analyseArticleList.AnalyseUrlList();
                foreach (string url in analyseArticleList.ArticleList)
                {
                    if (RepeatTimes > Config.ConfigManage.Instace().GetConfig().RepeatMax)
                        return;

                    //GetNovel("http://www.qidian.com/Book/2164996.aspx", ref analyseArticle);
                    GetNovel(url, ref analyseArticle);
                    analyseBookReader.Article = analyseArticle.Article;
                    if (string.IsNullOrEmpty(analyseArticle.Article.contentslink))
                    {
                        Utils.LogManage.Instace().Error("[10006]article contentslink is empty");
                        Utils.LogManage.Instace().Error(url);
                    }
                    GetBookReaders(ref analyseArticle, ref analyseBookReader);
                    NovelStore.Instace().StoreNovel(ref analyseArticle);
                    analyseBookReader.Article = analyseArticle.Article;
                    analyseChapter.Article = analyseArticle.Article;

                    if (NovelStore.Instace().StoreChapters("", ref analyseBookReader,  analyseChapter))
                    {
                        NovelStore.Instace().CompleteStore();
                        if (analyseBookReader.HasVipChapter > 0)
                        {
                            GetVipBookReader(analyseBookReader);
                        }
                    }
                }
            }
        }

        private void GetNovel(string articleLink, ref AnalyseArticle analyseArticle)
        {
            analyseArticle.SetContent(Utils.HttpHelper.Get(articleLink, analyseArticle.Encode));
            analyseArticle.AnalyseNovelInfo();
 
#if DEBUG
            PrintNovel(analyseArticle.Rule.RuleID.Pattern, analyseArticle.Article);
#endif
        }

        private void GetBookReaders(ref AnalyseArticle analyseArticle, ref AnalyseBookReader analyseBookReader)
        {
            analyseBookReader.Article = analyseArticle.Article;
            analyseBookReader.SetContent(Utils.HttpHelper.Get(analyseArticle.Article.contentslink, analyseArticle.Encode));
            analyseBookReader.AnalyseVolumeList();
#if DEBUG
            PrintChapters(analyseArticle.Rule.RuleID.Pattern, analyseBookReader.BookReader);
#endif
        }

        /// <summary>
        /// 存储所有备用规则与QIDIAN之间匹配的章节映射
        /// </summary>
        private readonly Dictionary<string, Dictionary<int, int>> _reserveRelations = new Dictionary<string, Dictionary<int, int>>();

        private class DiffernceInfo
        {
            public string webflag { get; set; }
            public int difference { get; set; }
        }

        private readonly IList<DiffernceInfo> _reserveDifferences = new List<DiffernceInfo>();

        private void GetVipBookReader(AnalyseBookReader sourceBookReader)
        {
            var hasBestBefore = false;
            var reserveRules = SmartMatch.Instace().GetReserveRules(sourceBookReader.Article.articleid, out hasBestBefore);
            _reserveRelations.Clear();
            _reserveDifferences.Clear();
            var article = sourceBookReader.Article;
            foreach (var reserveRule in reserveRules)
            {
                var analyse = GetAnalyserAll(reserveRule);
                var analyseArticle = analyse.AnalyseArticler;
                var analyseBookReader = analyse.AnalyseBookReaderer;
                var analyseChapter = analyse.AnalyseChapter;

                SearchNovel(sourceBookReader.Article, reserveRule, ref analyseArticle);
                analyseArticle.Article.articleid = sourceBookReader.Article.articleid;
                analyseBookReader.Article = analyseArticle.Article;
                if (string.IsNullOrEmpty(analyseArticle.Article.contentslink))
                {
                    Utils.LogManage.Instace().Error("[10007]article contentslink is empty");
                    Utils.LogManage.Instace().Error(sourceBookReader.Article.articlename);
                    return;
                }
                GetBookReaders(ref analyseArticle, ref analyseBookReader);
                if (Config.ConfigManage.Instace().GetConfig().GatherType == "APP")
                {
                    NovelStore.Instace().StoreChapters(reserveRule.RuleID.Pattern, ref analyseBookReader, analyseChapter);
                }

                int difference = 0;
                var relations = new Dictionary<int, int>();
                var hasBest = SmartMatch.Instace().MatchChapters(sourceBookReader.BookReader, analyseBookReader.BookReader, ref difference, ref relations);
                if (hasBest)
                {
                    Utils.LogManage.Instace().Info(true, string.Format("[BEST]{0}{1}", article.articlename, article.contentslink));
                    if (Config.ConfigManage.Instace().GetConfig().GatherType == "WEB")
                    {
                        NovelStore.Instace().DownloadTxtReserve(sourceBookReader, analyseBookReader, analyseChapter, relations);
                    }
                    NovelStore.Instace().SaveBestMatch(article, reserveRule.RuleID.Pattern, hasBestBefore);
                }
                else
                {
                    _reserveRelations[reserveRule.RuleID.Pattern] = relations; //将章节映射关系存入
                    _reserveDifferences.Add(new DiffernceInfo {webflag = reserveRule.RuleID.Pattern, difference = difference});
                }
            }
            //所有备用站点未查询出best，则取用difference最少的规则
            if (_reserveDifferences.Count > 0 && Config.ConfigManage.Instace().GetConfig().GatherType == "WEB")
            {
                var items = from s in _reserveDifferences
                            orderby s.difference descending
                            select s;
                DiffernceInfo diff = items.First();
                NovelStore.Instace().DownloadTxtReserve(sourceBookReader,
                                                        _dicAnalyser[diff.webflag].AnalyseBookReaderer,
                                                        _dicAnalyser[diff.webflag].AnalyseChapter,
                                                        _reserveRelations[diff.webflag]);
            }
        }

        private AnalyserAll GetAnalyserAll(RuleEntity reserveRule)
        {
            if (!_dicAnalyser.ContainsKey(reserveRule.RuleID.Pattern))
            {
                var analyse = new AnalyserAll
                                  {
                                      AnalyseArticler = new AnalyseArticle { Rule = reserveRule },
                                      AnalyseBookReaderer = new AnalyseBookReader { Rule = reserveRule },
                                      AnalyseChapter = new AnalyseChapter { Rule = reserveRule }
                                  };
                _dicAnalyser[reserveRule.RuleID.Pattern] = analyse;
            }
            return _dicAnalyser[reserveRule.RuleID.Pattern];
        }

        /// <summary>
        /// 通过查询方式采集小说信息页
        /// </summary>
        /// <param name="article"></param>
        /// <param name="reserveRule"></param>
        /// <param name="analyseArticle"></param>
        private void SearchNovel(ArticleInfo article, RuleEntity reserveRule, ref AnalyseArticle analyseArticle)
        {
            //获取查找的URL
            var searchLink = analyseArticle.AnalyseNovelSearchUrl(article.articlename);
            analyseArticle.SetContent(Utils.HttpHelper.Get(searchLink, Encoding.GetEncoding(reserveRule.GetSiteCharset.Pattern)));
            //从查询的HTML分析出article url
            searchLink = analyseArticle.GetNovelLink(article.articlename);
            if (string.IsNullOrEmpty(searchLink))
            {
                //从article url采集
                analyseArticle.AnalyseNovelInfo();
#if DEBUG
                PrintNovel(analyseArticle.Rule.RuleID.Pattern, analyseArticle.Article);
#endif
            }
            else
            {
                GetNovel(searchLink, ref analyseArticle);
            }
        }



        //private void GetVipChapters(AnalyseBookReader sourceBookReader)
        //{
        //            Config.ConfigManage.Instace().MoveSecondFirst();
        //            for (var i = 0; i < Config.ConfigManage.Instace().GetSecondRuleSize(); i++)
        //            {
        //                if(!_dicAnalyser.ContainsKey(Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern))
        //                {
        //                    var analyse = new AnalyserAll
        //                                      {
        //                                          AnalyseArticler =
        //                                              new AnalyseArticle {Rule = Config.ConfigManage.Instace().GetSecondRule()},
        //                                          AnalyseBookReaderer =
        //                                              new AnalyseBookReader
        //                                                  {Rule = Config.ConfigManage.Instace().GetSecondRule()},
        //                                          AnalyseChapter =
        //                                              new AnalyseChapter {Rule = Config.ConfigManage.Instace().GetSecondRule()}
        //                                      };
        //                    _dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern] = analyse;
        //                }

        //                var analyseArticle =
        //                    _dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern].AnalyseArticler;
        //                var analyseBookReader =
        //                    _dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern].AnalyseBookReaderer;
        //                var analyseChapter =
        //                    _dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern].AnalyseChapter;

        //                //获取查找的URL
        //                var searchLink = analyseArticle.AnalyseNovelSearchUrl(sourceBookReader.Article.articlename);
        //                analyseArticle.SetContent(Utils.HttpHelper.Get(searchLink,
        //                                                                  Encoding.GetEncoding(
        //                                                                      Config.ConfigManage.Instace().GetSecondRule().
        //                                                                          GetSiteCharset.Pattern)));
        //                //从查询的HTML分析出article url
        //                searchLink = analyseArticle.GetNovelLink(sourceBookReader.Article.articlename);
        //                if (string.IsNullOrEmpty(searchLink))
        //                {
        //                    //从article url采集
        //                    analyseArticle.AnalyseNovelInfo();
        //#if DEBUG
        //                    PrintNovel(analyseArticle.Article);
        //#endif
        //                }
        //                else
        //                {
        //                    GetNovel(searchLink, ref analyseArticle);
        //                }
        //                analyseBookReader.Article = analyseArticle.Article;
        //                GetBookReaders(ref analyseArticle, ref analyseBookReader);

        //                _dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern].DiffCount =
        //                    GetDifferentCount(sourceBookReader, analyseBookReader);

        //                //比对采集回来的章节数是否等于源章节数
        //                if (_dicAnalyser[Config.ConfigManage.Instace().GetSecondRule().RuleID.Pattern].DiffCount == 0)
        //                {
        //                    //下载TXT
        //                    NovelStore.Instace().StoreChaptersBySecond(sourceBookReader, analyseBookReader, ref analyseChapter);
        //                    return;
        //                }
        //                //不等于源章节数,继续采集备用站
        //                //需要标记出VIP章节或者只少的章节，或者下载时由文件是否存在判断
        //                Config.ConfigManage.Instace().MoveSecondNext();
        //            }
        //            //从所有备用站中，查找出章节数最多的

        //            //从选中的备用站中，采集TXT
        //}

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="source">qidian</param>
        ///// <param name="target"></param>
        ///// <returns></returns>
        //private int GetDifferentCount(AnalyseBookReader source, AnalyseBookReader target)
        //{
        //    var result = 0;
        //    for (int si = 0; si < source.BookReader.Count; si++)
        //    {
        //        if (source.BookReader[si].chaptertype == 0)//去除卷
        //        {
        //            if (!target.BookReader.Contains(source.BookReader[si]))
        //            {
        //                result++;
        //            }
        //        }
        //    }
        //    return result;
        //}

    }
}
